package edu.tec.mty.core.modules;

import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//import java.util.concurrent.locks.Condition;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import edu.tec.mty.core.modules.models.*;

public class Self { // extends Thread {
	
	public static int STATUS = 0;
	
	public final static int IDLE = 0;
	public final static int WILL_TO_DASH = 1;
	public final static int DASHING = 2;
	public final static int WILL_TO_TURN = 3;
	public final static int TURNING = 4;
	public final static int WILL_TO_STOP = 5;
	
	public static String SIDE = "left";
	public static int    UNUM = 0;
	
	//            Player parameter                       Default value
	public static int    ALLOW_MULT_DEFAULT_TYPE              = 0;
	public static double CATCHABLE_AREA_L_STRECH_MAX          = 1.3;
	public static double CATCHABLE_AREA_L_STRECH_MIN          = 1.0;
	public static double DASH_POWER_RATE_DELTA_MAX            = 0.0;
	public static double DASH_POWER_RATE_DELTA_MIN            = 0.0;
	public static double EFFORT_MAX_DELTA_FACTOR              = -0.004;
	public static double EFFORT_MIN_DELTA_FACTOR              = -0.004;
	public static double EXTRA_STAMINA_DELTA_MAX              = 50.0;
	public static double EXTRA_STAMINA_DELTA_MIN              = 0.0;
	public static double FOUL_DETECT_PROBABILITY_DELTA_FACTOR = 0.0;
	public static double INERTIA_MOMENT_DELTA_FACTOR          = 25.0;
	public static double KICK_POWER_RATE_DELTA_MAX            = 0.0;
	public static double KICK_POWER_RATE_DELTA_MIN            = 0.0;
	public static double KICK_RAND_DELTA_FACTOR               = 1.0;
	public static double KICKABLE_MARGIN_DELTA_MAX            = 0.1;
	public static double KICKABLE_MARGIN_DELTA_MIN            = -0.1;
	public static double NEW_DASH_POWER_RATE_DELTA_MAX        = 0.0008;
	public static double NEW_DASH_POWER_RATE_DELTA_MIN        = -0.0012;
	public static double NEW_STAMINA_INC_MAX_DELTA_FACTOR     = -6000.0;
	public static double PLAYER_DECAY_DELTA_MAX               = 0.1;
	public static double PLAYER_DECAY_DELTA_MIN               = -0.1;
	public static double PLAYER_SIZE_DELTA_FACTOR             = -100.0;
	public static double PLAYER_SPEED_MAX_DELTA_MAX           = 0.0;
	public static double PLAYER_SPEED_MAX_DELTA_MIN           = 0.0;
	public static int    PLAYER_TYPES                         = 18;
	public static int    PT_MAX                               = 1;
	public static int    RANDOM_SEED                          = 1325632690;
	public static double STAMINA_INC_MAX_DELTA_FACTOR         = 0.0;
	public static int    SUBS_MAX                             = 3;
	
	//            Player type parameter      Default value
	public static int    TYPE_ID                  = 0;
	public static double PLAYER_SPEED_MAX         = 1.05;
	public static double STAMINA_INC_MAX          = 45.0;
	public static double PLAYER_DECAY             = 0.4;
	public static double INERTIA_MOMENT           = 5.0;
	public static double DASH_POWER_RATE          = 0.006;
	public static double PLAYER_SIZE              = 0.3;
	public static double KICKABLE_MARGIN          = 0.7;
	public static double KICK_RAND                = 0.1;
	public static double EXTRA_STAMINA            = 50.0;
	public static double EFFORT_MAX               = 1.0;
	public static double EFFORT_MIN               = 0.6;
	public static double KICK_POWER_RATE          = 0.027;
	public static double FOUL_DETECT_PROBABILITY  = 0.5;
	public static double CATCHABLE_AREA_L_STRETCH = 1.0;
	
	private int[]    typesId;
	private double[] playerSpeedMax;
	private double[] staminaIncMax;
	private double[] playerDecay;
	private double[] inertiaMoment;
	private double[] dashPowerRate;
	private double[] playerSize;
	private double[] kickableMargin;
	private double[] kickRand;
	private double[] extraStamina;
	private double[] effortMax;
	private double[] effortMin;
	private double[] kickPowerRate;
	private double[] foulDetectProbability;
	private double[] catchableAreaLStretch;
	
	//                     Sense body parameter        Default value
	public volatile static String   VIEW_MODE_WIDTH    = "high";
	public volatile static String   VIEW_MODE_QUALITY  = "normal";
	public volatile static double   STAMINA            = 8000.0;
	public volatile static double   EFFORT             = 1.0;
	public volatile static double   STAMINA_CAPACITY   = 130600.0;
	public volatile static double   AMOUNT_OF_SPEED    = 0.0;
	public volatile static double   DIRECTION_OF_SPEED = 0.0;
	public volatile static double   HEAD_ANGLE         = 0.0;
	public volatile static int      KICK_COUNT         = 0;
	public volatile static int      DASH_COUNT         = 0;
	public volatile static int      TURN_COUNT         = 0;
	public volatile static int      SAY_COUNT          = 0;
	public volatile static int      TURN_NECK_COUNT    = 0;
	public volatile static int      CATCH_COUNT        = 0;
	public volatile static int      MOVE_COUNT         = 0;
	public volatile static int      CHANGE_VIEW_COUNT  = 0;
	public volatile static int      ARM_MOVABLE        = 0;
	public volatile static int      ARM_EXPIRES        = 0;
	public volatile static double   ARM_DIST           = 0.0;
	public volatile static double   ARM_DIR            = 0.0;
	public volatile static int      ARM_COUNT          = 0;
	public volatile static String   FOCUS_TARGET       = "none";
	public volatile static int      FOCUS_COUNT        = 0;
	public volatile static int      TACKLE_EXPIRES     = 0;
	public volatile static int      TACKLE_COUNT       = 0;
	public volatile static String[] COLLISION          = {"none"};
	public volatile static int      FOUL_CHARGED       = 0;
	public volatile static String   FOUL_CARD          = "none";
	
	static class NeckAngleBuffer {
		
		private int limit = 10;
		private TreeMap<Long, Double> map = new TreeMap<Long, Double>();
		
		public synchronized void add(long time, double neckAngle) {
			if (map.size() < limit) {
				map.put(time, neckAngle);
			} else {
				long older = map.firstKey();
				map.remove(older);
				map.put(time, neckAngle);
			}
		}
		
		public synchronized double getNeckAngleAtTime(long time) {
			return map.get(time);
		}
		
	}
	
	static class SpeedBuffer {
		
		private int limit = 10;
		private TreeMap<Long, Double> amountMap = new TreeMap<Long, Double>();
		private TreeMap<Long, Double> dirMap = new TreeMap<Long, Double>();
		
		public synchronized void add(long time, double amount, double dir) {
			if (amountMap.size() < limit) {
				amountMap.put(time, amount);
				dirMap.put(time, dir);
			} else {
				long older = amountMap.firstKey();
				amountMap.remove(older);
				dirMap.remove(older);
				amountMap.put(time, amount);
				dirMap.put(time, dir);
			}
		}
		
		public synchronized double getAmountOfSpeedAtTime(long time) {
			return amountMap.get(time);
		}
		
		public synchronized double getDirectionOfSpeedAtAtime(long time) {
			return dirMap.get(time);
		}
		
	}
	
	public static Pattern senseBodyPattern = Pattern.compile(
			"^\\(sense_body\\s+\\d+\\s+" +
					"\\(view_mode\\s+(\\w+)\\s+(\\w+)\\)\\s*" + //group 1 group 2
					"\\(stamina\\s+(\\d+|\\d+\\.\\d+)\\s+(\\d+|\\d+\\.\\d+)\\s+(\\d+|\\d+\\.\\d+)\\)\\s*" + //group 3 group 4 group 5
					"\\(speed\\s+(\\-?\\d+|\\d+\\.\\d+)\\s\\-?(\\d+|\\d+\\.\\d+)\\)\\s*" + //group 6 group 7
					"\\(head_angle\\s+(\\-?\\d+|\\d+\\.\\d+)\\)\\s*" + //group 8
					"\\(kick\\s+(\\d+)\\)\\s*" + //group 9
					"\\(dash\\s+(\\d+)\\)\\s*" + //group 10
					"\\(turn\\s+(\\d+)\\)\\s*" + //group 11
					"\\(say\\s+(\\d+)\\)\\s*" + //group 12
					"\\(turn_neck\\s+(\\d+)\\)\\s*" + //group 13
					"\\(catch\\s+(\\d+)\\)\\s*" + //group 14
					"\\(move\\s+(\\d+)\\)\\s*" + //group 15
					"\\(change_view\\s+(\\d+)\\)\\s*" + //group 16
					"\\(arm\\s+" +
						"\\(movable\\s+(\\d+)\\)\\s*" + //group 17
						"\\(expires\\s+(\\d+)\\)\\s*" + //group 18
						"\\(target\\s+(\\d+|\\d+\\.\\d+)\\s+(\\d+|\\d+\\.\\d+)\\)\\s*" + //group 19 20
						"\\(count\\s+(\\d+)\\)\\s*" + //group 21
					"\\)\\s*" +
					"\\(focus\\s+" +
						"\\(target\\s+(none|[lr]\\s+\\d+)\\)\\s*" + //group 22
						"\\(count\\s+(\\d+)\\)\\s*" + //group 23
					"\\)\\s*" +
					"\\(tackle\\s+" +
	   					"\\(expires\\s+(\\d+)\\)\\s*" + //group 24
	   					"\\(count\\s+(\\d+)\\)\\s*" + //group 25
	   				"\\)\\s*" +
	   				"\\(collision\\s+(none|\\(ball\\)|\\(player\\)|\\(ball\\)\\s+\\(player\\)|\\(ball\\)\\s+\\(player\\)\\s+\\(post\\))\\)\\s*" + //group 26
	   				"\\(foul\\s+" +
	   					"\\(charged\\s+(\\d+)\\)\\s*" + //group 27
	   					"\\(card\\s+(none|yellow|red)\\)\\s*" + //group 28
	   				"\\)\\s*" +
			"\\)$");
	
	private String stringBody;
	private SelfModel playerModel;
	private long step = 0;
	public long lastStepUpdated = 0;
	private int number;
//	private boolean running = true;
	private final Lock lock = new ReentrantLock();
//	private final Condition update = lock.newCondition();
//	private boolean updating = false;
//	private boolean closing = false;
	public static NeckAngleBuffer BUFFER = new NeckAngleBuffer();
	public static SpeedBuffer SPEED_BUFFER = new SpeedBuffer();

	public Self(String playerParams, String side, int number) {
		SIDE = side;
		UNUM = number;
		int index = playerParams.indexOf(' ');
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		String[] tokens = playerParams.substring(1, index).split(" ", 2);
		Self.ALLOW_MULT_DEFAULT_TYPE = Integer.parseInt(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.CATCHABLE_AREA_L_STRECH_MAX          = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.CATCHABLE_AREA_L_STRECH_MIN          = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.DASH_POWER_RATE_DELTA_MAX            = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.DASH_POWER_RATE_DELTA_MIN            = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.EFFORT_MAX_DELTA_FACTOR              = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.EFFORT_MIN_DELTA_FACTOR              = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.EXTRA_STAMINA_DELTA_MAX              = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.EXTRA_STAMINA_DELTA_MIN              = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.FOUL_DETECT_PROBABILITY_DELTA_FACTOR = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.INERTIA_MOMENT_DELTA_FACTOR          = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.KICK_POWER_RATE_DELTA_MAX            = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.KICK_POWER_RATE_DELTA_MIN            = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.KICK_RAND_DELTA_FACTOR               = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.KICKABLE_MARGIN_DELTA_MAX            = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.KICKABLE_MARGIN_DELTA_MIN            = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.NEW_DASH_POWER_RATE_DELTA_MAX        = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.NEW_DASH_POWER_RATE_DELTA_MIN        = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.NEW_STAMINA_INC_MAX_DELTA_FACTOR     = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.PLAYER_DECAY_DELTA_MAX               = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.PLAYER_DECAY_DELTA_MIN               = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.PLAYER_SIZE_DELTA_FACTOR             = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.PLAYER_SPEED_MAX_DELTA_MAX           = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.PLAYER_SPEED_MAX_DELTA_MIN           = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.PLAYER_TYPES                         = Integer.parseInt(tokens[1]);
		this.typesId = new int[Self.PLAYER_TYPES];
		this.playerSpeedMax = new double[Self.PLAYER_TYPES];
		this.staminaIncMax = new double[Self.PLAYER_TYPES];
		this.playerDecay = new double[Self.PLAYER_TYPES];
		this.inertiaMoment = new double[Self.PLAYER_TYPES];
		this.dashPowerRate = new double[Self.PLAYER_TYPES];
		this.playerSize = new double[Self.PLAYER_TYPES];
		this.kickableMargin = new double[Self.PLAYER_TYPES];
		this.kickRand = new double[Self.PLAYER_TYPES];
		this.extraStamina = new double[Self.PLAYER_TYPES];
		this.effortMax = new double[Self.PLAYER_TYPES];
		this.effortMin = new double[Self.PLAYER_TYPES];
		this.kickPowerRate = new double[Self.PLAYER_TYPES];
		this.foulDetectProbability = new double[Self.PLAYER_TYPES];
		this.catchableAreaLStretch = new double[Self.PLAYER_TYPES];
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.PT_MAX                               = Integer.parseInt(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.RANDOM_SEED                          = Integer.parseInt(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.STAMINA_INC_MAX_DELTA_FACTOR         = Double.parseDouble(tokens[1]);
		playerParams = playerParams.substring(index + 1);
		index = playerParams.indexOf(')');
		tokens = playerParams.substring(1, index).split(" ", 2);
		Self.SUBS_MAX                             = Integer.parseInt(tokens[1]);
		this.playerModel = new SelfModel(side, 0);
		this.number = number;
		this.playerModel.start();
	}
	
	public void changeStatus(int status) {
		this.lock.lock();
		STATUS = status;
		this.lock.unlock();
	}
	
	public int getPlayerNumber() {
		return this.number;
	}
	
	public void addPlayerType(String playerType) {
		int index = playerType.indexOf(' ');
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		String[] tokens = playerType.substring(1, index).split(" ", 2);
		int typeId = Integer.parseInt(tokens[1]);
		this.typesId[typeId] = Integer.parseInt(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.playerSpeedMax[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.staminaIncMax[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.playerDecay[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.inertiaMoment[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.dashPowerRate[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.playerSize[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.kickableMargin[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.kickRand[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.extraStamina[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.effortMax[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.effortMin[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.kickPowerRate[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.foulDetectProbability[typeId] = Double.parseDouble(tokens[1]);
		playerType = playerType.substring(index + 1);
		index = playerType.indexOf(')');
		tokens = playerType.substring(1, index).split(" ", 2);
		this.catchableAreaLStretch[typeId] = Double.parseDouble(tokens[1]);
	}
	
	public void setPlayerType(int type) {
		this.lock.lock();
		Self.TYPE_ID                  = this.typesId[type];
		Self.PLAYER_SPEED_MAX         = this.playerSpeedMax[type];
		Self.STAMINA_INC_MAX          = this.staminaIncMax[type];
		Self.PLAYER_DECAY             = this.playerDecay[type];
		Self.INERTIA_MOMENT           = this.inertiaMoment[type];
		Self.DASH_POWER_RATE          = this.dashPowerRate[type];
		Self.PLAYER_SIZE              = this.playerSize[type];
		Self.KICKABLE_MARGIN          = this.kickableMargin[type];
		Self.KICK_RAND                = this.kickRand[type];
		Self.EXTRA_STAMINA            = this.extraStamina[type];
		Self.EFFORT_MAX               = this.effortMax[type];
		Self.EFFORT_MIN               = this.effortMin[type];
		Self.KICK_POWER_RATE          = this.kickPowerRate[type];
		Self.FOUL_DETECT_PROBABILITY  = this.foulDetectProbability[type];
		Self.CATCHABLE_AREA_L_STRETCH = this.catchableAreaLStretch[type];
		this.lock.unlock();
	}
	
	public void setGlobalTime(long step) {
		this.step = step;
		this.playerModel.setGlobalTime(step);
	}
	
	public long getGlobalTime() {
		return this.step;
	}
	
	public SelfModel getReferenceToPlayerModel() {
		return this.playerModel;
	}
	
	public void initPosition(double x, double y) {
		this.playerModel.updateXY(x, y);
	}
	
	public Position getPosition() {
		return this.playerModel.getPosition();
	}
	
	public Position getPositionAtTime(long time) {
		return this.playerModel.getPositionAtTime(time);
	}
	
	public void updateBody(String body, long step) {
		this.lock.lock();
		if (step > this.lastStepUpdated) {
			this.stringBody = body;
//			this.updating = true;
//			this.update.signal();
			this.lastStepUpdated = step;
			this.updateSenseBody();
		}
		this.lock.unlock();
	}
	
//	public void shutdown() {
//		this.lock.lock();
//		this.playerModel.shutdown();
//		this.running = false;
//		this.closing = true;
//		this.updating = true;
//		this.update.signal();
//		this.lock.unlock();
//	}
	
	private void updateSenseBody() {
		Matcher matcher = Self.senseBodyPattern.matcher((CharSequence)this.stringBody);
		if (matcher.matches()) {
			VIEW_MODE_QUALITY  = matcher.group(1);
			VIEW_MODE_WIDTH    = matcher.group(2);
			STAMINA            = Double.parseDouble(matcher.group(3));
			EFFORT             = Double.parseDouble(matcher.group(4));
			STAMINA_CAPACITY   = Double.parseDouble(matcher.group(5));
			AMOUNT_OF_SPEED    = Double.parseDouble(matcher.group(6));
			DIRECTION_OF_SPEED = Double.parseDouble(matcher.group(7));
			SPEED_BUFFER.add(lastStepUpdated, AMOUNT_OF_SPEED, DIRECTION_OF_SPEED);
			HEAD_ANGLE         = Double.parseDouble(matcher.group(8));
			Self.BUFFER.add(lastStepUpdated, HEAD_ANGLE);
			KICK_COUNT         = Integer.parseInt(matcher.group(9));
			DASH_COUNT         = Integer.parseInt(matcher.group(10));
			TURN_COUNT         = Integer.parseInt(matcher.group(11));
			SAY_COUNT          = Integer.parseInt(matcher.group(12));
			TURN_NECK_COUNT    = Integer.parseInt(matcher.group(13));
			CATCH_COUNT        = Integer.parseInt(matcher.group(14));
			MOVE_COUNT         = Integer.parseInt(matcher.group(15));
			CHANGE_VIEW_COUNT  = Integer.parseInt(matcher.group(16));
			ARM_MOVABLE        = Integer.parseInt(matcher.group(17));
			ARM_EXPIRES        = Integer.parseInt(matcher.group(18));
			ARM_DIST           = Double.parseDouble(matcher.group(19));
			ARM_DIR            = Double.parseDouble(matcher.group(20));
			ARM_COUNT          = Integer.parseInt(matcher.group(21));
			FOCUS_TARGET       = matcher.group(22);
			FOCUS_COUNT        = Integer.parseInt(matcher.group(23));
			TACKLE_EXPIRES     = Integer.parseInt(matcher.group(24));
			TACKLE_COUNT       = Integer.parseInt(matcher.group(25));
			COLLISION          = matcher.group(26).split("\\s");
			FOUL_CHARGED       = Integer.parseInt(matcher.group(27));
			FOUL_CARD          = matcher.group(28);
			switch (STATUS) {
			case IDLE:
				break;
			case WILL_TO_STOP:
				STATUS = IDLE;
				break;
			case WILL_TO_DASH:
				break;
			case WILL_TO_TURN:
				break;
			case DASHING:
				if (AMOUNT_OF_SPEED < 0.1) {
					STATUS = WILL_TO_STOP;
				}
				break;
			case TURNING:
				break;
			}
		} else {
			System.out.println("Error in matching: " +  this.stringBody);
		}
	}
	
//	@Override
//	public void run() {
//		while(this.running) {
//			this.lock.lock();
//			try {
//				while(!this.updating) {
//					this.update.await();
//				}
//			} catch (Exception e) {
//				System.err.println(e);
//			}
//			if (!this.closing) {
//				this.updateSenseBody();
//			}
//			this.updating = false;
//			this.lock.unlock();
//		}
//		System.out.println("Player closed");
//	}
	
	//Test
	
	/*public static void main(String[] args) {
		String test = "(sense_body 0 (view_mode high normal) (stamina 8000 1 130600) (speed 0 0) (head_angle 0) (kick 0) (dash 0) (turn 0) (say 0) (turn_neck 0) (catch 0) (move 0) (change_view 0) (arm (movable 0) (expires 0) (target 0 0) (count 0)) (focus (target none) (count 0)) (tackle (expires 0) (count 0)) (collision none) (foul  (charged 0) (card none)))";
		Matcher matcher = Player.senseBodyPattern.matcher(test);
		if (matcher.matches()) {
			System.out.println("matches");
		} else {
			System.out.println("doesnt matches");
		}
	} /**/
	
}
